/*
 * @(#)StandardMailRetriever.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.mail.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.bean.AbstractBaseObject;
import com.dcivision.mail.bean.MailSetting;
import com.dcivision.mail.dao.MailSettingDAObject;

public class StandardMailRetriever extends com.dcivision.framework.dao.AbstractDAObject {

  public static final String REVISION = "$Revision: 1.7.42.2 $";

 
  public static final String PRIMARY_FOLDER_NAME = "INBOX";
  public static final String POP3_RETRIEVER = "pop3";
  public static final String IMAP_RETRIEVER = "imap";

  protected SessionContainer sessionContainer;
  protected Connection dbConn;
  protected MessageBoxProfile msgBoxProfile;
  protected Session session;
  protected Store store;
  protected Folder[] folderList;
  protected int folderAccessType;

  public MessageBoxProfile getMessageBoxProfile() {
    return this.msgBoxProfile;
  }

  public StandardMailRetriever(SessionContainer sessionContainer, Connection dbConn) throws ApplicationException {
    this.sessionContainer = sessionContainer;
    this.dbConn = dbConn;
    this.retrieveProfile();
    this.open();
  }

  protected void retrieveProfile() throws ApplicationException {
    MailSettingDAObject mailSettingDAO = new MailSettingDAObject(this.sessionContainer, this.dbConn);
    MailSetting mailSetting = (MailSetting)mailSettingDAO.getObjectByUserRecordID(this.sessionContainer.getUserRecordID());
    if (mailSetting != null) {
      this.msgBoxProfile = new MessageBoxProfile();
      msgBoxProfile.setHost(mailSetting.getIncomingServerHost());
      msgBoxProfile.setPort(mailSetting.getIncomingServerPort() == null ? -1 : mailSetting.getIncomingServerPort().intValue());
      msgBoxProfile.setUsername(mailSetting.getIncomingServerLoginName());
      msgBoxProfile.setPassword(mailSetting.getIncomingServerLoginPwd());
      msgBoxProfile.setProtocol(mailSetting.getMailServerType());
    }
  }

  protected void resolveAttachment(Part part, List list) throws MailRetrieverException {
    try {
      Object obj = part.getContent();
      if (Part.ATTACHMENT.equals( (part.getDisposition()))) {
        MailAttachment attach = new MailAttachment();
        attach.setFileName(part.getFileName());
        attach.setContentType(part.getContentType());
//        attach.setContentSize(part.getSize());
        if (obj instanceof InputStream) {
          InputStream istream = (InputStream) obj;
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          int length = -1;
          int bufferSize = 512;
          byte[] buffer = new byte[bufferSize];
          while ( (length = istream.read(buffer, 0, bufferSize)) != -1) {
            baos.write(buffer, 0, length);
          }
          byte[] temporaryData = baos.toByteArray();
          attach.setInputStream(new ByteArrayInputStream(temporaryData));
          attach.setContentSize(temporaryData.length);
          baos.close();
          istream.close();
//        attach.setInputStream((InputStream) obj);
        }
        list.add(attach);
      } else if (obj instanceof Multipart) {
        Multipart mp = (Multipart) obj;
        final int partCount = mp.getCount();
        for (int i = 0; i < partCount; i++) {
          resolveAttachment(mp.getBodyPart(i), list);
        }
      }
    } catch (Exception e) {
      log.error(e, e);
      throw new MailRetrieverException();
    }
  }

  public Folder[] getFolderList() {
    return this.folderList;
  }

  public Store getStore() {
    return this.store;
  }

  public void open() throws MailRetrieverException {
    if (this.msgBoxProfile == null) {
      return;
    }
    try {
      Properties prop = System.getProperties();
      session = session.getDefaultInstance(prop, null);
      session.setDebug(false);
      store = session.getStore(msgBoxProfile.getProtocol());
      log.debug("msgBoxProfile.getHost()="+msgBoxProfile.getHost());
      log.debug("msgBoxProfile.getPort()="+msgBoxProfile.getPort());
      log.debug("msgBoxProfile.getUsername()="+msgBoxProfile.getUsername());
      log.debug("msgBoxProfile.getPassword()="+msgBoxProfile.getPassword());
      
      store.connect(msgBoxProfile.getHost(), msgBoxProfile.getPort(),
                    msgBoxProfile.getUsername(), msgBoxProfile.getPassword());
      Folder primaryFolder = store.getFolder(PRIMARY_FOLDER_NAME);
      if (IMAP_RETRIEVER.equals(msgBoxProfile.getProtocol())) {
        Folder folder = folder = store.getDefaultFolder();
        Folder[] tmpList = folder.listSubscribed("*");
        if (primaryFolder.exists()) {
          this.folderList = new Folder[tmpList.length + 1];
          System.arraycopy(tmpList, 0, folderList, 1, tmpList.length);
          this.folderList[0] = primaryFolder;
        } else {
          this.folderList = new Folder[tmpList.length];
          System.arraycopy(tmpList, 0, folderList, 0, tmpList.length);
        }
      } else if (POP3_RETRIEVER.equals(msgBoxProfile.getProtocol())) {
        this.folderList = new Folder[1];
        this.folderList[0] = primaryFolder;
      }
    } catch (Exception e) {
      log.error(e, e);
      throw new MailRetrieverException();
    }
  }

  public void close() throws MailRetrieverException {
    try { store.close(); } catch (Exception e) {} finally { store = null; }
  }

  public List getEmailMessageList(com.dcivision.framework.web.AbstractSearchForm searchForm) throws MailRetrieverException {
    List list = new ArrayList();
    com.dcivision.dms.web.ListDmsEmailArchiveForm emailArchiveForm = 
      (com.dcivision.dms.web.ListDmsEmailArchiveForm)searchForm;
    int folderID = new Integer(emailArchiveForm.getFolderID()).intValue() - 1;

    if (folderID < 0) {
      return list;
    }

    Folder folder = this.folderList[folderID];
    int startOffset = com.dcivision.framework.TextUtility.parseInteger(searchForm.getCurStartRowNo());
    int pageSize = com.dcivision.framework.TextUtility.parseInteger(searchForm.getPageOffset());
    int endOffset = startOffset - 1 + pageSize;

    try {
      if ((Folder.HOLDS_MESSAGES & folder.getType()) == 0) {
        return null;
      }
      folder.open(Folder.READ_ONLY);
      int msgCnt = folder.getMessageCount();
      if (endOffset > msgCnt) {
        endOffset = msgCnt;
      }
      Message[] msgs = folder.getMessages(startOffset, endOffset);
      for (int i = 0; i < msgs.length; i++) {
        MailMessage mailmsg = new MailMessage(msgs[i]);
//      List attachList = new ArrayList();
//      resolveAttachment(msgs[i], attachList);
//      mailmsg.setMailAttachmentList(attachList);
        mailmsg.setRecordCount(msgCnt);
        mailmsg.setRowNum(startOffset++);
        list.add(mailmsg);
      }
      return(list);
    } catch (Exception e) {
      log.error(e, e);
      throw new MailRetrieverException();
    }
  }

  
  public void finalize() throws Throwable {
    try { this.close(); } catch (Exception ignore) {}
    super.finalize();
  }

  // Protected methods which can be implemented by the sub-classes.
  
  protected AbstractBaseObject getByID(Integer id) throws ApplicationException {
    return null;
  }

  
  protected List getList(com.dcivision.framework.web.AbstractSearchForm searchForm) throws ApplicationException {
    return null;
  }

  
  protected List getList() throws ApplicationException {
    return null;
  }

  
  protected AbstractBaseObject insert(AbstractBaseObject obj) throws ApplicationException {
    return null;
  }

  
  protected AbstractBaseObject update(AbstractBaseObject obj) throws ApplicationException {
    return null;
  }

  
  protected AbstractBaseObject delete(AbstractBaseObject obj) throws ApplicationException {
    return null;
  }

  
  protected void auditTrail(String opMode, AbstractBaseObject obj) throws ApplicationException {
  }

  
  protected void initDBSetting() {
  }

  
  protected void validateInsert(AbstractBaseObject obj) throws ApplicationException {
  }

  
  protected void validateUpdate(AbstractBaseObject obj) throws ApplicationException {
  }

  
  protected void validateDelete(AbstractBaseObject obj) throws ApplicationException {
  }

}